package main

import "./model"
import "fmt"

// 继承：定义父类
type Aminal struct {
	Age    int
	Weight float32
}

// 定义结构体
type Cat struct {
	//为了复用性，体现继承思维，加入匿名结构体
	Aminal
	//绑定特有的属性
	name string
}

// 封装
// 封装就是把抽象出来的字段和字段操作封装到一起，数据被保护在内部，程序的其他包只有通过被授权的操作方法，才能对字段进行擦欧总
// 封装的好处，隐藏实现细节，可以对数据进行验证保证安全合理
func main() {

	//go中如何实现封装
	//1.建议将结构体，字段属性的首字母小写，类似与private
	//2.给结构体所在包提供一个工厂模式的函数，首字母大写
	//3.提供一个首字母大写的set方法，用于对属性判断并赋值 func (var 结构体类别名)SetXXX(参数列表){var.Age=参数 }
	//4.提供一个首字母大写的Get方法，用于获取属性值

	student := model.NewPerson("曾宇杰")
	// student.age=21这样是不行的，因为对age进行了封装
	student.SetAge(21)
	println(student.Name, student.GetName())
	fmt.Println(*student)

	//继承思想：提高代码的复用性
	//如果一个结构体嵌套了一个匿名结构体，那么这个结构体可以直接访问匿名结构体的字段和方法，从而实现继承特性
	cat1 := &Cat{}
	cat1.Aminal.Age = 1 //通过匿名结构体访问
	cat1.Aminal.Weight = 17
	cat1.Shout()
	cat1.Age = 12 //简化访问，如果父类没有相同的属性，可以这样直接调用age
	cat1.ShowInfo()
	cat1.scrach()

}

// 对Animal绑定通用方法，自我展示
func (a *Aminal) ShowInfo() {
	fmt.Printf("动物年龄：%d,动物体重:%f\n", a.Age, a.Weight)
}
func (a Aminal) Shout() {
	fmt.Printf("动物在叫")
}

// 对cat绑定特有的方法
func (c *Cat) scrach() {
	fmt.Println("猫猫挠人了")
}

//继承的注意事项
//1.结构体可以使用嵌套匿名结构体所有的字段和方法，即首字母大写或者小写的字段，方法，都可以使用
//2.匿名结构体字段访问可以化简，加入外层结构体和内层结构体的属性没有冲突，可以忽略掉内层结构体的类名
//3.当结构体和匿名结构体有相同的字段或者方法时，编译器采用就近原则访问，如希望访问匿名结构体的字段和方法，可以通过匿名结构体名来区分
//4.Golang中支持多继承，如一个结构体嵌套了多个匿名结构体，那么该结构体可以直接访问嵌套的匿名结构体的方法和字段，从而实现了多重继承，为了保证代码的简洁性，建议不适用多重继承
//5.如嵌入的匿名结构体有相同字段或者方法名，则在访问的时候，需要通过匿名结构体类型名来区分
//6.结构体的匿名字段可以是基本数据类型
//7.嵌套匿名结构体后，也可以在常见结构体变量时，直接指定各个匿名结构体的字段值
//8.嵌入匿名结构体的指针也是可以的
//9.结构体的字段可以是结构体类型的(组合模式)，就不是继承类型的，就是单纯的在结构体里含有结构体字段
